//
//  File_Operations.cpp
//  LearningOops
//
//  Created by Swetha Patnala on 4/21/13.
//  Copyright (c) 2013 Swetha Patnala. All rights reserved.
//

#include "File_Operations.h"


int File_Operations::fs_create(char* name){
    
    // getting the inode counter
    File_System_Manager *file;
    file =  File_System_Manager::getInstance();
    
    
    if( file->is_inode_full()){
        cout << " Cannot create a file since the inodes are full .No place to accomodate new inodes ";
        return -1;
    }
    
    /*
     int fileAlreadyCreated = inodeNumberOfTheFile(name);
     
     if ( fileAlreadyCreated > 0 ){
     cout << "The file was already created ";
     return -1;
     }
     */
    
    
    int inode_number = file->getFreeBitFromInodeBitmap();
    
    
    Inode *create_inode =  file->createNewInode(inode_number, name);
    
    create_inode->printInode();
    
    
    /*
     
     // getting free data block from databitmap
     int datablock_num = file->getFreeDataBitFromDataBitmap();
     
     
     //assigning value in the Data bitmap
     
     file->assignValueToDataBitmap(datablock_num);
     
     
     //allocating data block
     file->allocateDataBlocksToTheFile(datablock_num);
     
     //inofrming inode of the datablock address
     create_inode->set_Data_Block_num(datablock_num);
     
     */
    
    
    fs_open(name);
    
    
    
    
    //cout << " the inode number of the file is " << inodeNumberOfTheFile(name);
    
    
    return 0;
};


int File_Operations::fs_open(char* name){
    
    
    File_System_Manager *file;
    file =  File_System_Manager::getInstance();
    
    int inode_num_of_file = inodeNumberOfTheFile(name);
    if (inode_num_of_file < 0 ){
        return -1;
    }
    
    // printing inode info of the file
    
    Inode* open_inode = file->getInodeInfo(inode_num_of_file);
    
    // cout << "The Inode info of the file is " << open_inode <<endl;
    
    
    // assigning a file descriptor to the file
    
    int fd_count = open_inode->getFileDescriptorCount();
    int fd ;
    
    if(fd_count < 32 ){
        
        int fd_num = open_inode->getFreeFileDescriptor();
        // cout << "Allocating  file descriptor #  "<< fd_num <<endl;
        open_inode->allocateFileDescriptor(fd_num);
        fd= fd_num;
        
        
    }
    else{
        cout << " Reached the max file descriptor limit..so unable to open the file ";
        return -1;
    }
    
    return fd;
    
};


int File_Operations::fs_close(char* name , int fildes){
    
    File_System_Manager *file;
    file =  File_System_Manager::getInstance();
    
    int inode_num_of_file = inodeNumberOfTheFile(name);
    if (inode_num_of_file < 0 ){
        return -1;
    }
    
    
    
    // If the file is found , removing the file descriptor
    if (inode_num_of_file > 0){
        
        Inode* close_file = file->getInodeInfo(inode_num_of_file);
        
        if ( close_file->isFileDescriptorAvailable(fildes)){
            
            close_file->deallocateFileDescriptor(fildes);
            cout<< "Closed the file " << name << " of file descriptor " << fildes <<endl;
            
        }
        else {
            cout<< "The file descriptor is not available ";
            return -1;
        }
    }
    
    return 0;
};




int File_Operations::fs_delete(char* name){
    
    // // cheking if file is there or not
    
    File_System_Manager *file;
    file =  File_System_Manager::getInstance();
    
    int inode_num_of_file = inodeNumberOfTheFile(name);
    if (inode_num_of_file < 0 ){
        return -1;
    }
    
    // checking if there are any open file descriptors
    Inode* inode_delete = file->getInodeInfo(inode_num_of_file);
    
    int fd_count = inode_delete->getFileDescriptorCount();
    
    if (fd_count >0 ){
        cout << "The file descritors are still available hence cannot delete the file " <<endl;
        return -1;
    }
    
    
    //deleting the data block
    
    vector <int> datablock_vector = inode_delete->getInodeVector();
    
    for(int i =0 ; i < datablock_vector.size() ; i++){
        
        //cout <<"Data block num is " << datablock_vector.at(i);
        file->deallocateDataBlocksToTheFile(datablock_vector.at(i));
        file->decrement_datablock_counter();
        file->increment_num_of_unallocated_datablocks();
        
        
    }
    
    
    
    file->freeInode(inode_num_of_file);
    file->increment_num_of_unallocated_inodes();
    file->decrement_inode_counter();
    
    
    //cout << "Inode Bitmap value " <<endl;
    //file->printInodeBitMap();
    return 0;
    
    
}



int File_Operations::fs_write(char* name , int fildes, void *buf, size_t nbyte){
    
    
    
    File_System_Manager *file;
    file =  File_System_Manager::getInstance();
    
    // cheking if file is there or not
    
    int inode_num_of_file = inodeNumberOfTheFile(name);
    if (inode_num_of_file < 0 ){
        return -1;
    }
    
    // checking if file descriptor is valid or not
    Inode* inode_info  = file->getInodeInfo(inode_num_of_file);
    bool check_fd = inode_info->isFileDescriptorAvailable(fildes);
    if(!check_fd){
        cout<<"Invalid file descriptor "<<endl;
        return -1;
    }
    
    // writing to the datablock
    int datablock_num= file->getFreeDataBitFromDataBitmap();
    
    //allocating data block
    file->allocateDataBlocksToTheFile(datablock_num);
    
    file->writeDataBlock(datablock_num, buf);
    
    //assigning value in the Data bitmap
    
    file->assignValueToDataBitmap(datablock_num);
    inode_info->increment_num_of_datablocks();
    file->increment_datablock_counter();
    
    file->decrement_unallocated_datablock_num(1);
    
    inode_info->addToInodeVector(datablock_num);
    
    //file->printDataOftheFile(inode_num_of_file);
    
    
    
    //int inode_datablock = inode_info->get_Data_Block_num();
    //file->writeDataBlock(inode_datablock, buf);
    
    //inode_info->fd[fildes]->fd_current = nbyte;
    inode_info->get_inode_structure()->fd[fildes]->fd_current = (int) nbyte;
    
    
    //file->printDataOftheFile(inode_num_of_file);
    
    
    time_t file_modification_time = inode_info->getCurrentTime();
    inode_info->set_ModifiedTime(file_modification_time);
    
    //inode_info->printInode();
    return 0;
}



int File_Operations::fs_read(char* name ,int fildes, void *buf, size_t nbyte){
    
    
    
    File_System_Manager *file;
    file =  File_System_Manager::getInstance();
    
    // cheking if file is there or not
    
    int inode_num_of_file = inodeNumberOfTheFile(name);
    if (inode_num_of_file < 0 ){
        return -1;
    }
    
    // checking if file descriptor is valid or not
    Inode* inode_info  = file->getInodeInfo(inode_num_of_file);
    bool check_fd = inode_info->isFileDescriptorAvailable(fildes);
    if(!check_fd){
        cout<<"Invalid file descriptor "<<endl;
        return -1;
    }
    
    time_t file_access_time =inode_info->getCurrentTime();
    inode_info->set_LastAccessTime(file_access_time);
    
    //inode_info->printInode();
    file->printDataOftheFile(inode_num_of_file);
    return 0;
}




int File_Operations::inodeNumberOfTheFile(char *name){
    
    File_System_Manager *file;
    file =  File_System_Manager::getInstance();
    
    bool file_found = false;
    int inode_number = -1;
    for(int i = 1 ; i < NUM_OF_INODES+1 ; i++){
        
        char* file_name = file->getInodeArrayName(i);
        //cout<< "the file name is "<<file_name<<endl;
        if(name == file_name){
            file_found = true;
            inode_number = i;
            return inode_number;
            break;
        }
    }
    
    if(!file_found){
        cout << "Oops..!! The file was not created  ";
        return -1;
    }
    return inode_number;
    
}






